// ============================================================================
//  _ __   ___  ___  ___ _ __ ___  _   _
// | '_ \ / _ \/ __|/ _ \ '_ ` _ \| | | |
// | | | |  __/\__ \  __/ | | | | | |_| |
// |_| |_|\___||___/\___|_| |_| |_|\__,_|
//
// NES Emulator by daxnet, 2024
// MIT License
// ============================================================================

using NesEmu.Console.Models;
using NesEmu.Console.Palettes;
using NesEmu.Console.Properties;

namespace NesEmu.Console;

public partial class FrmMain : Form
{
    private readonly ConsoleSettings _settings;

    #region Public Constructors

    public FrmMain()
    {
        InitializeComponent();

        _settings = ConsoleSettings.Load();

        ResetWindowSize();
        BindViewModeSelection();
        LoadColorPalettes();

        gameControl1.GameOpened += GameControl1_GameOpened;
        gameControl1.GameStopped += GameControl1_GameStopped;

        gameControl1.SelectedControllerSetting = _settings.Controllers?[0] ?? ControllerSetting.Default;
    }

    #endregion Public Constructors

    #region Protected Methods

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        mnuClose.Enabled = false;
        mnuGameHardwareReset.Enabled = false;
    }

    #endregion Protected Methods

    #region Private Methods

    private void BindViewModeSelection()
    {
        var menuItems = new ToolStripMenuItem[] { mnuViewDebug, mnuViewFullscreen, mnuViewNormal, mnuViewScaled };
        foreach (var item in menuItems)
        {
            item.Checked = Convert.ToInt32(item.Tag) == _settings.SelectedViewMode;
        }

        var viewMode = (GameControl.ViewMode)_settings.SelectedViewMode;
        gameControl1.GameViewMode = viewMode;
    }

    private void Action_ChangeViewMode(object? sender, EventArgs e)
    {
        if (sender is ToolStripMenuItem menuItem)
        {
            var viewModeValue = Convert.ToInt32(menuItem.Tag);
            _settings.SelectedViewMode = viewModeValue;
            BindViewModeSelection();
        }
    }

    private void Action_SelectColorPalette(object? sender, EventArgs e)
    {
        if (sender is ToolStripMenuItem { Tag: ColorPalette colorPalette } menuItem)
        {
            gameControl1.SelectedColorPalette = colorPalette;
            _settings.SelectedColorPalette = menuItem.Text;
            foreach (ToolStripMenuItem item in mnuGameColorPalettes.DropDownItems)
            {
                item.Checked = menuItem == item;
            }
        }
    }

    private void GameControl1_GameOpened(object? sender, EventArgs e)
    {
        mnuClose.Enabled = true;
        mnuGameHardwareReset.Enabled = true;
    }

    private void GameControl1_GameStopped(object? sender, EventArgs e)
    {
        mnuClose.Enabled = false;
        mnuGameHardwareReset.Enabled = false;
    }

    private void LoadColorPalettes()
    {
        mnuGameColorPalettes.DropDownItems.Clear();
        foreach (var paletteItem in ColorPalette.Palettes.OrderBy(x => x.Key))
        {
            var paletteMenuItem = (ToolStripMenuItem)mnuGameColorPalettes.DropDownItems.Add(paletteItem.Key, Resources.palette);
            paletteMenuItem.Tag = paletteItem.Value;
            paletteMenuItem.Checked = paletteItem.Key == _settings.SelectedColorPalette;
            paletteMenuItem.Click += Action_SelectColorPalette;
        }
    }

    private void mnuClose_Click(object sender, EventArgs e)
    {
        gameControl1.StopGame();
    }

    private void mnuExit_Click(object sender, EventArgs e)
    {
        if (gameControl1.IsGameRunning)
        {
            gameControl1.StopGame();
        }

        Close();
    }

    private void mnuGameReset_Click(object sender, EventArgs e)
    {
        if (MessageBox.Show("Are you sure to reset the game?", "Confirmation", MessageBoxButtons.YesNo,
                MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
        {
            gameControl1.ResetGame();
        }
    }

    private void mnuOpenFromDir_Click(object sender, EventArgs e)
    {
        using var frm = new FrmDirFileList();
        if (frm.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(frm.SelectedFileName))
        {
            OpenGameRomFile(frm.SelectedFileName);
        }
    }

    private void mnuOpenRomFile_Click(object sender, EventArgs e)
    {
        if (openRomFileDlg.ShowDialog() == DialogResult.OK)
        {
            OpenGameRomFile(openRomFileDlg.FileName);
        }
    }

    private void OpenGameRomFile(string fileName)
    {
        try
        {
            if (gameControl1.IsGameRunning)
            {
                gameControl1.StopGame();
            }

            gameControl1.OpenGame(fileName);
        }
        catch (NotSupportedException)
        {
            MessageBox.Show("The selected ROM file is not supported.", "Error", MessageBoxButtons.OK,
                MessageBoxIcon.Error);
        }
    }

    private void ResetWindowSize()
    {
        gameControl1.Size = new Size(768, 720);
        ClientSize = new Size(gameControl1.Width, gameControl1.Height + MainMenuStrip?.Height ?? 0);
        gameControl1.Left = 0;
        gameControl1.Top = MainMenuStrip?.Height ?? 0;
        gameControl1.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;
    }

    #endregion Private Methods

    private void mnuGameControllerSettings_Click(object sender, EventArgs e)
    {
        var controllerSettingsForm = new FrmControllerSettings(_settings);
        if (controllerSettingsForm.ShowDialog(this) == DialogResult.OK)
        {
            _settings.Controllers ??= [];
            _settings.Controllers[0] = controllerSettingsForm.Setting;
            gameControl1.SelectedControllerSetting = controllerSettingsForm.Setting;
        }
    }

    private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
    {
        ConsoleSettings.Save(_settings);
    }
}